/*
 * Copyright (c) 2017 Simon Goldschmidt
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Simon Goldschmidt
 *
 */


#include "../arch/sys_arch.h"

#include "lwip/debug.h" // lwIP 调试日志相关宏定义
#include <lwip/stats.h> // lwIP 性能统计模块（统计信号量、邮箱等资源使用）
#include "lwip/mem.h"   // lwIP 内存管理模块（此处未直接使用，预留依赖）
#include <lwip/sys.h>   // lwIP 系统抽象层接口定义（需当前文件实现）
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "lwip/netif.h"
#include "lwip/sio.h"
#include "lwip/dhcp.h"
#include "ethernetif.h"
#include <string.h>

int errno;


struct sys_timeouts
{
  	struct sys_timeo *next;
};

struct timeoutlist
{
    struct sys_timeouts timeouts;
	xTaskHandle pid;
};

/* 最大支持创建的 lwIP 线程数（通过 sys_thread_new 创建的线程上限） */
#define SYS_THREAD_MAX     4

/* 线程超时链表 */
static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX];

/* 线程计数变量：跟踪已创建的 lwIP 线程数量，避免超过上限 */
static uint16_t s_nextthread = 0;



/* 返回当前时间（以滴答为单位） */
uint32_t sys_jiffies(void)
{
	return xTaskGetTickCount();
}
/* 返回当前时间（以毫秒为单位） */
uint32_t sys_now(void)
{
	return sys_jiffies() * portTICK_PERIOD_MS;
}


/* lwIP 系统适配层初始化 */
void sys_init(void)
{
	// 初始化每个线程的sys_timeouts结构, 确保列表中没有有效的进程ID
	for (size_t i = 0; i < SYS_THREAD_MAX; i++)
	{
	    s_timeoutlist[i].pid = 0;
	    s_timeoutlist[i].timeouts.next = NULL;
	}
	// 重置线程计数器（初始为 0，无已创建线程）
	s_nextthread = 0;
}

/* 获取当前任务的超时链表 */
struct sys_timeouts *sys_arch_timeouts(void)
{
	xTaskHandle pid;
	struct timeoutlist *tl;
	
	pid = xTaskGetCurrentTaskHandle( );

	for (size_t i = 0; i < s_nextthread; i++)
	{
	    tl = &(s_timeoutlist[i]);
	    if(tl->pid == pid)
	    {
		    return &(tl->timeouts);
		}
	}
	return NULL;
}

/* 系统架构保护 */
int sys_arch_protect(void)
{
	/* 调用 FreeRTOS 的进入临界区函数（关闭中断） */
	vPortEnterCritical();
	return 1;
}
/* 系统架构解除保护 */
void sys_arch_unprotect(int pval)
{
	( void ) pval;
	/* 调用 FreeRTOS 的退出临界区函数（恢复中断） */
	vPortExitCritical();
}


/* 创建信号量 */
err_t sys_sem_new(sys_sem_t *sem, uint8_t count)
{
    /* 创建 sem */
    if(count <= 1)
    {    
        *sem = xSemaphoreCreateBinary();
        if(count == 1)
        {
            sys_sem_signal(*sem);
        }
    }
    else
        *sem = xSemaphoreCreateCounting(count,count);
  
#if SYS_STATS
	// 已使用信号量数 +1
	++lwip_stats.sys.sem.used;
 	if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used)
    {
	    lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
	}
#endif /* SYS_STATS */

	// 检查信号量创建结果
    if(*sem != SYS_SEM_NULL)
    	return ERR_OK;
    else
    {
#if SYS_STATS
    	++lwip_stats.sys.sem.err;
#endif /* SYS_STATS */
    	printf("[sys_arch]:new sem fail!\n");
    	return ERR_MEM;
  	}
}
/* 销毁信号量 */
void sys_sem_free(sys_sem_t *sem)
{
#if SYS_STATS
	--lwip_stats.sys.sem.used;
#endif /* SYS_STATS */
  	// 调用 FreeRTOS API 销毁信号量
  	vSemaphoreDelete(*sem);
  	*sem = SYS_SEM_NULL;
}
/* 检查信号量句柄是否有效 */
int sys_sem_valid(sys_sem_t *sem)
{
  	return *sem == SYS_SEM_NULL ? 0 : 1;                                    
}
/* 将信号量句柄设为无效 */
void sys_sem_set_invalid(sys_sem_t *sem)
{
  	*sem = SYS_SEM_NULL;
}
/* 等待信号量（阻塞式，支持超时） */
uint32_t sys_arch_sem_wait(sys_sem_t *sem, uint32_t timeout)
{
  	uint32_t wait_tick = 0;
  	uint32_t start_tick = 0 ;
  
  	//看看信号量是否有效
  	if(*sem == SYS_SEM_NULL)
    	return SYS_ARCH_TIMEOUT;
  
  	//首先获取开始等待信号量的时钟节拍
  	start_tick = xTaskGetTickCount();
  
  	//timeout != 0，需要将ms换成系统的时钟节拍
  	if(timeout != 0)
  	{
    	//将ms转换成时钟节拍
    	wait_tick = timeout / portTICK_PERIOD_MS;
    	if (wait_tick == 0)
      		wait_tick = 1;
  	}
  	else
    	wait_tick = portMAX_DELAY;  //一直阻塞
  
  	//等待成功，计算等待的时间，否则就表示等待超时
  	if(xSemaphoreTake(*sem, wait_tick) == pdTRUE)
    	return ((xTaskGetTickCount()-start_tick)*portTICK_RATE_MS);
  	else
    	return SYS_ARCH_TIMEOUT;
}
/* 释放信号量 */
void sys_sem_signal(sys_sem_t *sem)
{
  	if (xSemaphoreGive(*sem) != pdTRUE)
    	printf("[sys_arch]:sem signal fail!\n");
}

/* 创建新的互斥锁 */
err_t sys_mutex_new(sys_mutex_t *mutex)
{
  	/* 调用 FreeRTOS 的 API 创建一个互斥锁（递归锁） */
  	*mutex = xSemaphoreCreateMutex();

  	if (*mutex == SYS_SEM_NULL)
	{
#if SYS_STATS
        /* 增加互斥锁错误计数 */
        ++lwip_stats.sys.mutex.err;
#endif /* SYS_STATS */
    	printf("[sys_arch]:new mutex fail!\n");
    	return ERR_MEM;
	}

#if SYS_STATS
    /* 增加已使用互斥锁数量 */
    ++ lwip_stats.sys.mutex.used;

    /* 更新最大使用数 */
    if (lwip_stats.sys.mutex.max < lwip_stats.sys.mutex.used) {
        lwip_stats.sys.mutex.max = lwip_stats.sys.mutex.used;
    }
#endif /* SYS_STATS */
  	
	return ERR_OK; /* 创建成功 */
}
/* 释放（删除）互斥锁 */
void sys_mutex_free(sys_mutex_t *mutex)
{
#if SYS_STATS
    /* 减少已使用互斥锁数量 */
    -- lwip_stats.sys.mutex.used;
#endif /* SYS_STATS */
  	vSemaphoreDelete(*mutex);
}
/* 设置互斥锁无效 */
void sys_mutex_set_invalid(sys_mutex_t *mutex)
{
  	*mutex = SYS_SEM_NULL;
}
/* 锁定互斥锁（阻塞等待） */
void sys_mutex_lock(sys_mutex_t *mutex)
{
	sys_arch_sem_wait(*mutex, 0);
}
/* 解锁互斥锁 */
void sys_mutex_unlock(sys_mutex_t *mutex)
{
	/* 释放互斥锁 */
  	xSemaphoreGive( *mutex );
}

/* 创建一个新线程 */
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
{
  	sys_thread_t handle = NULL;
  	BaseType_t xReturn = pdPASS;
  	/*                                  任务入口函数            任务名字          任务栈大小  任务入口函数参数   任务的优先级          任务控制块指针*/
  	xReturn = xTaskCreate((TaskFunction_t)function, (const char*)name, (uint16_t)stacksize,(void*)arg, (UBaseType_t)prio, (TaskHandle_t*)&handle);
  	if(xReturn != pdPASS)
  	{
    	printf("[sys_arch]:create task fail!err:%#lx\n",xReturn);
    	return NULL;
  	}
  	return handle;
}

/* 创建空邮箱 */
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
{  
  	/*                       消息队列的长度               消息的大小*/
  	*mbox = xQueueCreate((UBaseType_t)size, (UBaseType_t)sizeof(void*));

#if SYS_STATS  // 若启用 lwIP 统计功能，更新邮箱使用统计
    ++lwip_stats.sys.mbox.used;  // 已使用邮箱数 +1
    if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used)
	{
        lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;  // 更新最大使用数
    }
#endif /* SYS_STATS */

    // 检查队列创建结果：NULL 表示内存不足
	return *mbox == NULL ? ERR_MEM : ERR_OK;
}
/* 销毁邮箱 */
void sys_mbox_free(sys_mbox_t *mbox)
{
	// 检查邮箱中是否还有未处理的消息
  	if (uxQueueMessagesWaiting(*mbox))
	{
		portNOP();// 空操作，用于调试断点（正常情况下不应进入此分支）
#if SYS_STATS
	    lwip_stats.sys.mbox.err++;// 邮箱错误计数 +1（销毁时有残留消息）
#endif /* SYS_STATS */
		// TODO: 可添加用户通知（如日志打印），提示销毁时有残留消息
	}
	// 调用 FreeRTOS API 销毁队列（邮箱）
  	vQueueDelete(*mbox);

#if SYS_STATS
    --lwip_stats.sys.mbox.used;// 已使用邮箱数 -1
#endif /* SYS_STATS */
}
/* 检查邮箱句柄是否有效 */
int sys_mbox_valid(sys_mbox_t *mbox)
{
	return *mbox == SYS_MBOX_NULL ? 0 : 1;
}   
/* 将邮箱句柄设为无效 */
void sys_mbox_set_invalid(sys_mbox_t *mbox)
{
  	*mbox = SYS_MBOX_NULL; 
}
/* 向邮箱发送一条消息（阻塞式） */
void sys_mbox_post(sys_mbox_t *q, void *msg)
{
  	// 阻塞发送消息到队列尾部：超时时间为 portMAX_DELAY（无限等待，直到成功）
  	while(xQueueSend( *q, &msg, portMAX_DELAY) != pdTRUE);
}
/* 尝试向邮箱发送消息（非阻塞式） */
err_t sys_mbox_trypost(sys_mbox_t *q, void *msg)
{
	// 非阻塞发送消息：超时时间为 0（立即返回）
  	if(xQueueSend(*q, &msg, 0) == pdPASS)
	{
		return ERR_OK;
	}
  	else
	{
#if SYS_STATS
        lwip_stats.sys.mbox.err++;  // 邮箱错误计数 +1
#endif /* SYS_STATS */
		return ERR_MEM;
	}
}
/* 中断里尝试向邮箱发送消息（非阻塞式） */
err_t sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
{
  	return sys_mbox_trypost(q, msg);
}
/* 从邮箱接收消息（阻塞式，支持超时） */
uint32_t sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, uint32_t timeout)
{
  	void *dummyptr;
  	uint32_t wait_tick = 0;
  	uint32_t start_tick = 0 ;

	// 若 msg 为 NULL，用 dummyptr 接收消息（避免空指针访问）
  	if ( msg == NULL )
		msg = &dummyptr;
  
  	//首先获取开始等待信号量的时钟节拍
  	start_tick = sys_now();
  
  	//timeout != 0，需要将ms换成系统的时钟节拍
  	if(timeout != 0)
  	{
    	//将ms转换成时钟节拍
    	wait_tick = timeout / portTICK_PERIOD_MS;
    	if (wait_tick == 0)
      		wait_tick = 1;
  	}
  	else
    	wait_tick = portMAX_DELAY;
  
  	//等待成功，计算等待的时间，否则就表示等待超时
  	if(xQueueReceive(*q,&(*msg), wait_tick) == pdTRUE)
    	return ((sys_now() - start_tick)*portTICK_PERIOD_MS);
  	else
  	{
    	*msg = NULL;
    	return SYS_ARCH_TIMEOUT;
  	}
}
/* 尝试从邮箱接收消息（非阻塞式） */
uint32_t sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg)
{
	void *dummyptr;
	
	// 若 msg 为 NULL，用 dummyptr 接收消息
	if ( msg == NULL )
		msg = &dummyptr;
  
  	//等待成功，计算等待的时间
  	if(xQueueReceive(*q,&(*msg), 0) == pdTRUE)
    	return ERR_OK;
  	else
    	return SYS_MBOX_EMPTY;
}

#if LWIP_NETCONN_SEM_PER_THREAD
#error LWIP_NETCONN_SEM_PER_THREAD==1 not supported
#endif /* LWIP_NETCONN_SEM_PER_THREAD */






void WHT_LWIP_Init(void)
{
	static struct netif gnetif;
	ip4_addr_t IPADDR;
	ip4_addr_t NETMASK;
	ip4_addr_t GATEWAY;

	/* 创建TCPIP线程 */
	tcpip_init(NULL, NULL);
  
  	/* IP地址初始化 */
#if LWIP_DHCP
  	ip_addr_set_zero_ip4(&IPADDR);
  	ip_addr_set_zero_ip4(&NETMASK);
  	ip_addr_set_zero_ip4(&GATEWAY);
#else
  	IP4_ADDR(&IPADDR, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
  	IP4_ADDR(&NETMASK, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
  	IP4_ADDR(&GATEWAY, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
#endif /* USE_DHCP */
  	
  	/* 添加新的网络接口（IPv4/IPv6） */
	/* netif_add(struct netif *netif, struct ip_addr *ipaddr,
	             struct ip_addr *netmask, struct ip_addr *gw,
	             void *state, err_t (* init)(struct netif *netif),
	             err_t (* input)(struct pbuf *p, struct netif *netif))
	将你的网络接口添加到netif_list中。分配一个struct netif 并将指向该结构的指针作为第一个参数传递。
	使用DHCP时，提供指向已清空的ip_addr结构的指针，	否则，用合理的数值填充它们。state指针可以为NULL。
	init函数指针必须指向你的以太网netif接口的初始化函数。以下代码展示了它的用法。*/
  	netif_add(&gnetif, &IPADDR, &NETMASK, &GATEWAY, NULL, &ethernetif_init, &tcpip_input);

  	/* 设置默认网络接口 */
  	netif_set_default(&gnetif);

  	if (netif_is_link_up(&gnetif))
  	{
    	/* 网络接口链路连接 */
    	netif_set_up(&gnetif);
		printf("Netif up\r\n");
  	}
  	else
  	{
    	/* 网络接口链路断开 */
    	netif_set_down(&gnetif);
		printf("Netif down\r\n");
  	}

	/* 设置链接回调函数，此函数在链接状态改变时被调用 */
#if LWIP_NETIF_LINK_CALLBACK
	netif_set_link_callback(&gnetif, ethernetif_update_config);
#endif /* LWIP_NETIF_LINK_CALLBACK */

#if LWIP_NETIF_STATUS_CALLBACK
	netif_set_status_callback(&gnetif, ethernetif_update_config);
#endif /* LWIP_NETIF_STATUS_CALLBACK */

	/* 若使用了DHCP */
#if LWIP_DHCP
    /*  首次调用时为此接口创建一个新的DHCP客户端。
    注意：启动客户端后，必须按预定义的固定间隔调用dhcp_fine_tmr()和dhcp_coarse_tmr()。
    您可以查看netif->dhcp结构体以获取实际的DHCP状态。*/
   	printf("本例程将使用DHCP动态分配IP地址,如果不需要则在lwipopts.h中将LWIP_DHCP定义为0 \r\n");
  
	/* 启动DHCP */
  	if(dhcp_start(&gnetif) == ERR_MEM)
	{
		printf("lwip dhcp init fail...\n\n");
	}

	/* 等待DHCP分配的IP有效 */
  	while(ip_addr_cmp(&(gnetif.ip_addr), &IPADDR))
  	{
    	vTaskDelay(10);
  	}
#endif
  	printf("My IP Addr:%u.%u.%u.%u\n\n", (gnetif.ip_addr.addr >> 0) & 0xff, (gnetif.ip_addr.addr >> 8) & 0xff, (gnetif.ip_addr.addr >> 16) & 0xff, (gnetif.ip_addr.addr >> 24) & 0xff);
}
